package ru.reinvent.perspectiva.net;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

import ru.reinvent.perspectiva.cash.PerspectivaProvider;
import ru.reinvent.perspectiva.cash.Vendor;

import android.content.Context;
import android.os.Handler;

public class NetManager 
	{
	public static final String LOTS_CONTENT_URL = "http://lombard-perspectiva.ru/alllots.ashx";
	public static final String CATALOG_CASH_FILENAME = "catalog.xml"; 
	
	private static NetManager manager = null;
	private Thread lotsDownloadingThread = null;

	static { manager = new NetManager(); }
	
	public static NetManager get()
		{
		if (manager == null) { manager = new NetManager(); }
		return manager;
		}

	public boolean getLotsContent(final LotsDownloadListener listener, final long progressUpdateTimer, final String cashDirPath, final Context ctx)
		{
		if (lotsDownloadingThread!=null && lotsDownloadingThread.isAlive()) return false;
		
		final Handler mainThreadHandler = new Handler(); 
		lotsDownloadingThread = new Thread(new Runnable()
			{
			public void run() 
				{
				StringBuffer sb = null;
				BufferedReader in = null;
				try 
					{
					sb = new StringBuffer();
					URL url = new URL(LOTS_CONTENT_URL);
					HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

					final int lotsContentLength = urlConnection.getContentLength();
					downloadStarted(mainThreadHandler, lotsContentLength, listener);
					
					long progressLastUpdated = System.currentTimeMillis();
					in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
					int piece = -1;
					while ((piece = in.read()) != -1) 
						{
						sb.appendCodePoint(piece);
						
						boolean updateProgress = System.currentTimeMillis() > progressLastUpdated + progressUpdateTimer;
						if (lotsContentLength!=-1 && updateProgress) 
							{
							progressLastUpdated = System.currentTimeMillis();
							updateProgress(mainThreadHandler,lotsContentLength,sb.toString().getBytes().length,listener);
							}
						}
					in.close();					
					} 
				catch (Exception e) { sb = null; }
				finally { if (in != null) try { in.close(); } catch(Exception e) {;} }
				
				final String responce = (sb==null) ? null : sb.toString();
				if (responce == null) { downloadFailed(mainThreadHandler,listener); return; }
				else downloadFinished(mainThreadHandler,responce,listener); 
				
				if (cashDirPath != null)
					{
					File cashDir = new File(cashDirPath);
					File file = new File(cashDir,CATALOG_CASH_FILENAME);

					saveInFileStarted(mainThreadHandler,file,listener);
					FileWriter out = null;
					try 
						{
						if (!cashDir.exists()) cashDir.mkdirs();
						if (!file.exists()) file.createNewFile();

						out = new FileWriter(file);
						out.write(responce);
						out.flush();
						out.close();
					
						saveInFileFinished(mainThreadHandler,file,listener);
						} 
					catch (IOException e) { saveInFileFailed(mainThreadHandler,listener); }
					finally { try { if (out!=null) out.close(); } catch (IOException e) {;} }
					}

				parseStarted(mainThreadHandler,listener);
				ArrayList<Vendor> vendors = null;
        		try 
        			{ 
        			vendors = (new PerspectivaXMLParser()).parse(responce);
        			parseFinished(mainThreadHandler,vendors,listener); 
        			} 
        		catch (Exception e) { parseFailed(mainThreadHandler,listener); return; }
        		
				saveInDBStarted(mainThreadHandler,listener);
				try
					{
					final int[] meredState = PerspectivaProvider.DBUsage.mergeCash(vendors,ctx);
					saveInDBFinished(meredState,mainThreadHandler,listener);
					}
        		catch (Exception e) { saveInDBFailed(mainThreadHandler,listener); }
				}
			});
		
		lotsDownloadingThread.start();
		return true;
		}
	
	protected void downloadStarted(Handler mainThreadHandler, final int contentLength, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.downloadStarted(contentLength); 
				}
			});
		}
	
	protected void updateProgress(Handler mainThreadHandler, final int contentLength, final int contentDownloaded, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.updateProgress(contentLength,contentDownloaded); 
				}
			});
		}

	protected void downloadFailed(Handler mainThreadHandler, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.downloadFailed(); 
				}
			});
		}
	
	protected void downloadFinished(Handler mainThreadHandler, final String responce, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		if (responce == null) { downloadFailed(mainThreadHandler, listener); return; }
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.downloadFinished(responce); 
				}
			});
		}
	
	protected void parseStarted(Handler mainThreadHandler, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.parseStarted(); 
				}
			});
		}
	
	protected void parseFailed(Handler mainThreadHandler, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.parseFailed(); 
				}
			});
		}
	
	protected void parseFinished(Handler mainThreadHandler, final ArrayList<Vendor> parsed, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.parseFinished(parsed); 
				}
			});
		}

	protected void saveInFileStarted(Handler mainThreadHandler, final File file, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.saveInFileStarted(file); 
				}
			});
		}
	
	protected void saveInFileFailed(Handler mainThreadHandler, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.saveInFileFailed(); 
				}
			});
		}
	
	protected void saveInFileFinished(Handler mainThreadHandler, final File file, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.saveInFileFinished(file); 
				}
			});
		}

	protected void saveInDBStarted(Handler mainThreadHandler, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.saveInDBStarted(); 
				}
			});
		}
	
	protected void saveInDBFailed(Handler mainThreadHandler, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.saveInDBFailed(); 
				}
			});
		}
	
	protected void saveInDBFinished(final int[] mergeState, Handler mainThreadHandler, final LotsDownloadListener listener)
		{
		if (listener == null) return;
		mainThreadHandler.post(new Runnable() 
			{
			@Override
			public void run() 
				{ 
				listener.saveInDBFinished(mergeState[0],mergeState[1],mergeState[2],mergeState[3]); 
				}
			});
		}

	public void stopDownloadingLots()
		{
		try { lotsDownloadingThread.stop(); lotsDownloadingThread = null; }
		catch(Exception e) {;}
		}
	
	public interface LotsDownloadListener
		{
		public void downloadStarted(int contentLength);
		public void updateProgress(int contentLength, int contentDownloaded);
		public void downloadFailed();
		public void downloadFinished(String responce);
		public void parseStarted();
		public void parseFailed();
		public void parseFinished(ArrayList<Vendor> parsed);
		public void saveInFileStarted(File file);
		public void saveInFileFailed();
		public void saveInFileFinished(File file);
		public void saveInDBStarted();
		public void saveInDBFailed();
		public void saveInDBFinished(int vendorsAdded, int vendorsRemoved, int lotsAdded, int lotsRemoved);
		}
	
	public static class LotsDownloadAdapter implements LotsDownloadListener
		{
		@Override
		public void downloadStarted(int contentLength) {;}
		@Override
		public void updateProgress(int contentLength, int contentDownloaded) {;}
		@Override
		public void downloadFailed() {;}
		@Override
		public void downloadFinished(String responce) {;}
		@Override
		public void parseStarted() {;}
		@Override
		public void parseFailed() {;}
		@Override
		public void parseFinished(ArrayList<Vendor> parsed) {;}
		@Override
		public void saveInFileStarted(File file) {;}
		@Override
		public void saveInFileFailed() {;}
		@Override
		public void saveInFileFinished(File file) {;}
		@Override
		public void saveInDBStarted() {;}
		@Override
		public void saveInDBFailed() {;}
		@Override
		public void saveInDBFinished(int vendorsAdded, int vendorsRemoved, int lotsAdded, int lotsRemoved) {;}
		}
	}
